#include <iostream>
#include <stdio.h>
#include <vector>
#include <string>

#include "SDL/SDL.h"

using namespace std;

// Thingy for events
SDL_Event event;

// TODO: Add multiple levels
int LEVEL_WIDTH = 20;
int LEVEL_HEIGHT = 15;
string level = 
"...................."
"...................."
"...................."
"P..................."
"P..................."
"PPPP................"
"...P................"
"...P................"
".........PPP........"
"...................."
"....P..............."
".......P............"
"......PP............"
".....PPP............"
"P....PPPPP..........";


// Check for a collision between two SDL rects
bool collideRect(SDL_Rect a, SDL_Rect b) {
    return a.x + a.w > b.x and b.x + b.w > a.x and a.y + a.h > b.y and b.y + b.h > a.y;
}

// FPS handling
int nowtime, last_tick, end_time, raw_passed, delay_time;
void capFPS(int fps) {
    nowtime = SDL_GetTicks();
    last_tick = nowtime;
    end_time = ( 1000 / fps );
    raw_passed = SDL_GetTicks() - last_tick;
    delay_time = end_time - raw_passed;
    SDL_Delay ( delay_time );
}

class Platform {
    
    public:
        SDL_Rect rect;
        
        Platform(int x, int y) {
        
            // Set the dimensions for the rect
            rect.x = x;
            rect.y = y;
            rect.w = 16;
            rect.h = 16;
        }
};

class Player {

    public:
        SDL_Rect rect;
        float jump_speed, jump_accel;
        
        Player() {
            
            // Set the jump_speed to 0
            jump_speed = 0.0;
            jump_accel = 0.5;
            
            // Set the dimensions for the rect
            rect.x = 16;
            rect.y = 16;
            rect.w = 16;
            rect.h = 16;
        }
        
        // Call __move for x and y axes
        void move(int dx, int dy, vector<Platform> &platforms) {
            if( dx != 0 )
                __move(dx, 0, platforms);
            if( dy != 0 )
                __move(0, dy, platforms);
        }
        
        void jump() {
            jump_speed = -8.0;
        }
        
        void slowFall() {
            jump_accel = 0.5;
        }
        
        void normalFall() {
            jump_accel = 1.5;
        }
        
        // Move and check for collisions - dx or dy must be zero
        void __move(int dx, int dy, vector<Platform> &platforms) {
            rect.x += dx;
            rect.y += dy;
            
            for( int i=0; i<platforms.size(); i++ ) {
                if( collideRect(rect, platforms[i].rect) ) {
                    if( dx > 0 )
                        rect.x = platforms[i].rect.x-rect.w;
                    if( dx < 0 )
                        rect.x = platforms[i].rect.x+platforms[i].rect.w;
                    if( dy > 0 ) {
                        rect.y = platforms[i].rect.y-rect.h;
                        jump_speed = 0;
                    }
                    if( dy < 0 )
                        rect.y = platforms[i].rect.y+platforms[i].rect.h;
                }
            }
        }
};

int main(int argc, char** argv) {

    // Initialise SDL, or exit.
    if( SDL_Init(SDL_INIT_EVERYTHING) == -1 ) {
        printf( "Unable to init SDL. Sad Pandas.\n" );
        return 1;
    }
    
    // Quit SDL at exit
    atexit(SDL_Quit);
    
    // Rect for the dimensions of the screen
    SDL_Rect screenrect;
    screenrect.x = 0;
    screenrect.y = 0;
    screenrect.w = 320;
    screenrect.h = 240;
    
    // Set up the display
    SDL_WM_SetCaption( "platformer", "platformer" );
    SDL_Surface *screen = SDL_SetVideoMode( screenrect.w, screenrect.h, 32, SDL_SWSURFACE );
    
    // Hold the platforms in a vector :P
    vector <Platform> platforms;
    Player player = Player();
    
    // Level parser
    for( int y = 0; y < LEVEL_HEIGHT; y++ ) {
        for( int x = 0; x < LEVEL_WIDTH; x++ ) {
            int pos = y*LEVEL_WIDTH + x;
            if( level[pos] == 'P' )
                platforms.push_back(Platform(x*16, y*16));
        }
    }
    
    // Main loop
    int running = 1;
    while( running == 1 ) {
        
        // Cap the framerate at 30
        capFPS(30);
        
        // Check for input
        if( SDL_PollEvent(&event) ){
            if( event.type == SDL_QUIT ) {
                running = 0;
                break; // Makes it quit faster, lol
            }
            if( event.type == SDL_KEYDOWN ) {
                if( event.key.keysym.sym == SDLK_SPACE )
                    player.jump();
            }
        }
        
        // Check for currently held keys
        Uint8 *keystate = SDL_GetKeyState(0);
        
        // Move the player with the arrow keys
        if( keystate[SDLK_LEFT] ) {
            player.move(-3, 0, platforms);
        }
        if( keystate[SDLK_RIGHT] ) {
            player.move(3, 0, platforms);
        }
        if( keystate[SDLK_SPACE] ) {
            player.slowFall();
        } else {
            player.normalFall();
        }
        
        if( player.jump_speed < 8 )
            player.jump_speed += player.jump_accel;
        player.move(0, player.jump_speed, platforms);
        
        if( player.rect.x < 0 )
            player.rect.x = 0;
        if( player.rect.x > LEVEL_WIDTH*16 - player.rect.w )
            player.rect.x = LEVEL_WIDTH*16 - player.rect.w;
        if( player.rect.y < 0 )
            player.rect.y = 0;
        if( player.rect.y > LEVEL_HEIGHT*16 - player.rect.h )
            player.rect.y = LEVEL_HEIGHT*16 - player.rect.h;
        
        // Fill the screen with grey
        SDL_FillRect(screen, &screenrect, SDL_MapRGB(screen->format, 0, 0, 0));
        
        // Draw the platforms
        for( int i = 0; i < platforms.size(); i++ ) {
            SDL_FillRect(screen, &platforms[i].rect, SDL_MapRGB(screen->format, 255, 255, 255));
        }
        
        // Draw the player
        SDL_FillRect(screen, &player.rect, SDL_MapRGB(screen->format, 255, 200, 0));
        
        // Flip the display
        SDL_Flip( screen );
    }

    // Return an int at exit ^_^
    return 0;
}